package com.example.snakefinal;

import android.annotation.SuppressLint;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class Server implements Runnable {

    private final SnakeGame snakeGame;

    private static final List<ServerAdapter> CLIENTS = new ArrayList<>();

    public Server(SnakeGame snakeGame) {
        this.snakeGame = snakeGame;
    }

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
            while (true) {
                serverSocket = new ServerSocket(43991);
                Socket accept = serverSocket.accept();
                ServerAdapter target = new ServerAdapter(accept, snakeGame);
                CLIENTS.add(target);
                // 启动新线程
                new Thread(target).start();
                new Thread(() -> {
                    while (true) {
                        Message.AllInfo allInfo = new Message.AllInfo();
                        allInfo.type = "AllInfo";
                        allInfo.wall = snakeGame.walls;
                        allInfo.huo = snakeGame.huos;
                        allInfo.foods = snakeGame.FOOD;
                        allInfo.snakes = snakeData(snakeGame.snakes);
                        allInfo.state = snakeGame.CURRENT_STATE;
                        allInfo.weather = snakeGame.weather;
                        for (ServerAdapter client : CLIENTS) {
                            try {
                                if (client.status == 1) {
                                    client.sendMessage(allInfo);
                                }
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }).start();
            }
        } catch (IOException e) {
        }
    }

    // 客户端发送服务端.
    public static class ServerAdapter implements Runnable {

        private Socket socket;
        private SnakeGame snakeGame;
        private Snake snake;

        private int status;

        public ServerAdapter(Socket socket, SnakeGame snakeGame) {
            this.socket = socket;
            this.snakeGame = snakeGame;
        }

        @Override
        public void run() {
            try {

                while (true) {
                    InputStream inputStream = socket.getInputStream();
                    @SuppressLint({"NewApi", "LocalSuppress"})
                    int length = ByteUtils.bytesToInt(inputStream.readNBytes(4));
                    @SuppressLint({"NewApi", "LocalSuppress"})
                    byte[] bytes = inputStream.readNBytes(length);
                    callMessage(bytes);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                snakeGame.snakes.remove(snake);
            }
        }

        public void sendMessage(Object object) throws IOException {
            byte[] bytes = JsonUtil.toStr(object).getBytes();
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(bytes.length);
            outputStream.write(bytes);
        }

        public void callMessage(byte[] message) throws IOException {
            String msg = new String(message);
            Message.BasicMsg basicMsg = JsonUtil.fromStr(msg, Message.BasicMsg.class);
            // 初始化
            if (basicMsg.type.equals("HelloMsg")) {
                Message.HelloMsg helloMsg = JsonUtil.fromStr(msg, Message.HelloMsg.class);
                List<Snake> snakes = snakeGame.snakes;
                Message.JoinMsg joinMsg = new Message.JoinMsg();
                joinMsg.name = "game" + (snakes.size() + 2);
                snake = new Snake(snakeGame.getContext(), snakeGame.screenSize, helloMsg.skinResource);
                snake.getSegmentLocations().get(0).x = new Random().nextInt(snakeGame.screenSize.x - 400) + 200;
                snake.getSegmentLocations().get(0).y = new Random().nextInt(snakeGame.screenSize.y - 400) + 200;
                snake.switchHeading(Snake.Heading.values()[new Random().nextInt(4)]);
                snakes.add(snake);
                joinMsg.type = "JoinMsg";
                sendMessage(joinMsg);
                Message.AllInfo allInfo = new Message.AllInfo();
                allInfo.type = "AllInfo";
                allInfo.wall = snakeGame.walls;
                allInfo.huo = snakeGame.huos;
                allInfo.foods = snakeGame.FOOD;
                allInfo.snakes = snakeData(snakes);
                allInfo.state = snakeGame.CURRENT_STATE;
                allInfo.weather = snakeGame.weather;
                sendMessage(allInfo);
                status = 1;
            }

            // 移动
            if (basicMsg.type.equals("MOVE")) {
                Message.MoveMsg moveMsg = JsonUtil.fromStr(msg, Message.MoveMsg.class);
                snake.switchHeading(moveMsg.heading);
            }

        }
    }

    public static Map<String, Message.SnakeData> snakeData(List<Snake> snakes) {
        Map<String, Message.SnakeData> snakeData = new HashMap<>();
        for (Snake snake : snakes) {
            Message.SnakeData e = new Message.SnakeData();
            e.name = snake.name;
            e.heading = snake.getHeading();
            e.score = snake.getScore();
            e.segmentLocations = snake.getSegmentLocations();
            e.skinResource = snake.skinResource;
            snakeData.put(e.name, e);
        }
        return snakeData;
    }
}
